﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Yto.Entities;
using Yto.Linq;

namespace Yto.Repositories
{
    public abstract class BaseRepository<TE, TPK> : IBaseRepository<TE, TPK>
        where TE : class, IEntity<TPK>
    {
        public virtual TE Single(TPK id)
        {
            return Single(ExpressionHelper<TE, TPK>.CreateExpressForGetByID(id));
        }

        public abstract TE Single(Expression<Func<TE, bool>> expression);

        public abstract IQueryable<TE> GetAll();

        public abstract TE Insert(TE entity);



        public abstract TE Update(TE entity);

        public abstract void Delete(TE entity);

        public virtual Task<TE> UpdateAsync(TE entity)
        {
            return Task.FromResult(Update(entity));
        }

        public virtual Task DeleteAsync(TE entity)
        {
            Delete(entity);
            return Task.FromResult(0);
        }

        public abstract void Delete(TPK id);

        public virtual Task DeleteAsync(TPK id)
        {
            Delete(id);
            return Task.FromResult(0);
        }

        public virtual List<TE> GetList()
        {
            return GetAll().ToList();
        }

        public virtual Task<List<TE>> GetListAsync()
        {
            return Task.FromResult(GetList());
        }

        public virtual Task<TE> InsertAsync(TE entity)
        {
            return Task.FromResult(Insert(entity));
        }

        public virtual Task<bool> BatchInsertAsync(IEnumerable<TE> list)
        {
            return Task.FromResult(BatchInsert(list));
        }

        public abstract bool BatchInsert(IEnumerable<TE> list);

        public abstract bool DeleteAll();


        public virtual Task<bool> DeleteAllAsync()
        {
            return Task.FromResult(DeleteAll());
        }

        public virtual TE FirstOrDefault(TPK id)
        {
            return FirstOrDefault(ExpressionHelper<TE, TPK>.CreateExpressForGetByID(id));
        }

        public virtual Task<TE> FirstOrDefaultAsync(TPK id)
        {
            return Task.FromResult(FirstOrDefault(id));
        }

        public virtual TE FirstOrDefault(Expression<Func<TE, bool>> expression)
        {
            return GetAll().FirstOrDefault<TE>(expression);
        }

        public virtual Task<TE> FirstOrDefaultAsync(Expression<Func<TE, bool>> expression)
        {
            return Task.FromResult(FirstOrDefault(expression));
        }

        public virtual Task<List<TE>> GetListAsync(Expression<Func<TE, bool>> expression, int maxCount = 0)
        {
            return Task.FromResult(GetList(expression, maxCount));
        }

        public virtual List<TE> GetList(Expression<Func<TE, bool>> expression, int maxCount = 0)
        {
            var query = GetAll().Where(expression);

            if (maxCount > 0)
            {

                query = query.Take(maxCount);
            }

            return query.ToList();
        }

    }
}
